/*
 * DeviceUnit class is composed of the device interface registers and 
 * handles all device requests between the system and devices.
 * 
 * Component Register are the Device Index Register, the Device Buffer
 * Register and the Device Status Register.
 * 
 * Device requests are made through the get and put operations.  Purely
 * input devices will only be serviced through the get interface and 
 * purely output devices will only be serviced through the put interface
 * 
 * Output operations require that the Device Index Register be set and 
 * the Device Buffer Register be filled before the put operation is invoked.  
 * 
 * Input operations require that the Device Index Register be set before the
 * get operation is invoked which will pass operation onto the the device 
 * which will respond by filling the Device Buffer Register with data for 
 * consumption by the system.
 * 
 * Input devices that have data waiting for get will respond to queries through
 * the status interface by placing a status code into the Status register 
 * for analysis and response.
 * 
 * All devices enroll with the DeviceUnit upon startup ensuring each device
 * will be appropriately indexed when device operations are requested.
 * 
 * The boot interface will explicitly request the CardReader device to prep 
 * the system by loading the boot file directly into main memory. 
 * */

package cpu.components;

import cpu.datastores.*;
import cpu.interfaces.*;
import system.device.*;
import ui.Console;
import ui.Printer;
import ui.controls.ButtonBank;
import ui.controls.DialBank;
import ui.controls.SwitchBank;

public class DeviceUnit {
	// system is capable of referencing 32 devices
	private static final int LENGTH = 32;
	
	// devicetable is a list of all of the devices accessible to the controller
	private Device[] devicefile;
	
	// a reference to the cardreader so that the system can boot.
	// this object should only be used during the boot process.
	//private system.device.CardReader bootloader;
	
	// Device Identifier Register [0-31]
	public Register5 DID;
	
	// Device Buffer Register 
	public Register16 DBR;
	
	// Device Status Register
	public Register16 DSR;
	
	private cpu.components.CPU cpu;
	
    // device 0
    private Keyboard keyboard;
    // device 1
    private system.device.Printer printer;
    // device 2
    private CardReader cardreader;
	
	public DeviceUnit( cpu.components.CPU cpu, Console console, Printer printerUI ) {
		this.cpu = cpu;
		
		DID = new Register5( );
		DBR = new Register16( );
		DSR = new Register16( );
		
		devicefile = new Device[LENGTH];
		
		keyboard = new system.device.Keyboard( console, printerUI );
        printer = new system.device.Printer( printerUI );
        cardreader = new system.device.CardReader( );
        
        keyboard.enroll( system.device.Identifiers.DEVICE_KEYBOARD.ordinal( ), this );
        printer.enroll( system.device.Identifiers.DEVICE_PRINTER.ordinal( ), this );
        cardreader.enroll( system.device.Identifiers.DEVICE_CARDREADER.ordinal( ), this );

        console.ledbankCC0.enroll( system.device.Identifiers.DEVICE_LEDCC0.ordinal( ), this );
        console.ledbankCC1.enroll( system.device.Identifiers.DEVICE_LEDCC1.ordinal( ), this );
        console.ledbankCC2.enroll( system.device.Identifiers.DEVICE_LEDCC2.ordinal( ), this );
        console.ledbankCC3.enroll( system.device.Identifiers.DEVICE_LEDCC3.ordinal( ), this );

        console.ledbankR0.enroll( system.device.Identifiers.DEVICE_LEDR0.ordinal( ), this );
        console.ledbankR1.enroll( system.device.Identifiers.DEVICE_LEDR1.ordinal( ), this );
        console.ledbankR2.enroll( system.device.Identifiers.DEVICE_LEDR2.ordinal( ), this );
        console.ledbankR3.enroll( system.device.Identifiers.DEVICE_LEDR3.ordinal( ), this );
        
        console.ledbankPC.enroll( system.device.Identifiers.DEVICE_LEDPC.ordinal( ), this );
        console.ledbankIR.enroll( system.device.Identifiers.DEVICE_LEDIR.ordinal( ), this );
        
        console.ledbankX0.enroll( system.device.Identifiers.DEVICE_LEDX0.ordinal( ), this );
        console.ledbankEA.enroll( system.device.Identifiers.DEVICE_LEDEA.ordinal( ), this );
       
        console.ledbankMAR.enroll( system.device.Identifiers.DEVICE_LEDMAR.ordinal( ), this );
        console.ledbankMBR.enroll( system.device.Identifiers.DEVICE_LEDMBR.ordinal( ), this );

        console.ledbankMSR.enroll( system.device.Identifiers.DEVICE_LEDMSR.ordinal( ), this );
        console.ledbankMFR.enroll( system.device.Identifiers.DEVICE_LEDMFR.ordinal( ), this );

        console.ledbankCacheMAR.enroll( system.device.Identifiers.DEVICE_LEDCACHEMAR.ordinal( ), this );
        console.ledbankCacheMBR.enroll( system.device.Identifiers.DEVICE_LEDCACHEMBR.ordinal( ), this );

        console.ledbankBooting.enroll( system.device.Identifiers.DEVICE_LEDBOOT.ordinal( ), this );
        console.ledbankStop.enroll( system.device.Identifiers.DEVICE_LEDSTOP.ordinal( ), this );
        console.ledbankRun.enroll( system.device.Identifiers.DEVICE_LEDRUN.ordinal( ), this );

        console.switchbank.enroll( system.device.Identifiers.DEVICE_SWREGOVERRIDE.ordinal( ), this );
        console.registerSelector.enroll( system.device.Identifiers.DEVICE_SWREGOVERSELECT.ordinal( ), this );
        console.latencySelector.enroll( system.device.Identifiers.DEVICE_SWLATENCYSELECT.ordinal( ), this );

        console.IPL.enroll( system.device.Identifiers.DEVICE_BTNIPL.ordinal( ), this );
        console.StartStop.enroll( system.device.Identifiers.DEVICE_BTNSTARTSTOP.ordinal( ), this );
        console.Commit.enroll( system.device.Identifiers.DEVICE_BTNCOMMIT.ordinal( ), this );
        console.Step.enroll( system.device.Identifiers.DEVICE_BTNSTEP.ordinal( ), this );

	}
	
	// get a word from the device
	public void get( ) {
		int i = DID.toJavaInt( );
		devicefile[ i ].get( );
	}
	
	// put a word to the device
	public void put( ) {
		int i = DID.toJavaInt( );
		devicefile[ i ].put( );
	}
	
	// query the device status of a device
	public void status( ) {
		int i = DID.toJavaInt( );
		devicefile[ i ].status( );
	}
	
	// all devices must enroll with the deviceunit allowing each 
	// to be added to the device table for later indexing by device id
	public void enroll( int did, Device d ) {
		assert( did >= 0 && did < LENGTH );
		
		devicefile[ did ] = d;
	}

	// a method to allow the system to by prepared through the boot process.
	// the method allows the card reader to read a file containing program and
	// initial state information into main system memory
	public void boot( cpu.components.CPU cpu ) {
		cardreader.boot( cpu );
	}
}
